package com.ddone.finance.controller.admin;


import com.alibaba.excel.EasyExcel;
import com.ddone.common.exception.Assert;
import com.ddone.common.exception.BusinessException;
import com.ddone.common.result.Response;
import com.ddone.common.result.ResponseEnum;
import com.ddone.finance.pojo.dto.DictExcelDto;
import com.ddone.finance.pojo.entity.Dict;
import com.ddone.finance.service.DictService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 数据字典 前端控制器
 * </p>
 *
 * @author ddone
 * @since 2024-04-10
 */
@RestController
@RequestMapping("/core/admin/dict")
// @CrossOrigin
@Api(tags = {"字典管理"})
@Slf4j
public class AdminDictController {

    @Resource
    private DictService dictService;

    @Resource
    private RedisTemplate<String,Object> redisTemplate;


    @ApiOperation("导入Excel文件")
    @PostMapping("/import")
    public Response<Object> impotExcel(
            @ApiParam(value = "导入的Excel文件", required = true)
            @RequestParam("file") MultipartFile file) {
        if (!(file.getOriginalFilename().endsWith(".xls") ||
                file.getOriginalFilename().endsWith(".xlsx"))) {
            throw new BusinessException("上传文件必须为excel文件", -108);
        }
        if (file.getSize()==0) {
            throw new BusinessException("上传的文件内容为空", -107);
        }

        try {
            InputStream fileStream = file.getInputStream();
            dictService.importExcel(fileStream);
            return Response.ok().message("批量导入成功");
        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessException(ResponseEnum.UPLOAD_ERROR, e);
        }
    }

    @ApiOperation("导出Excel数据")
    @GetMapping("/export")
    public void exportExcel(HttpServletResponse response){
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            String  fileName = URLEncoder.encode("数据字典_"+new DateTime().toString("yyyyMMdd_HHmmss"),"UTF-8").replaceAll("\\+","%20");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            List<DictExcelDto> data = dictService.list().stream().map(dict -> {
                DictExcelDto excelDto = new DictExcelDto();
                BeanUtils.copyProperties(dict, excelDto);
                return excelDto;
            }).collect(Collectors.toList());
            EasyExcel.write(response.getOutputStream())
                    .sheet("数据字典")
                    .head(DictExcelDto.class)
                    .doWrite(data);
        } catch (Exception e) {
            e.printStackTrace();
            throw  new BusinessException(ResponseEnum.EXPORT_DATA_ERROR);
        }
    }

    @ApiOperation("导入Excel的模板")
    @GetMapping("/template")
    public void exportTemplate(HttpServletResponse response){
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            String fileName = URLEncoder.encode("数据字典模板","UTF-8").replaceAll("\\+","%20");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream())
                    .sheet("数据字典")
                    .head(DictExcelDto.class)
                    .doWrite(new ArrayList<DictExcelDto>());
        } catch (Exception e) {
            e.printStackTrace();
            throw  new BusinessException(ResponseEnum.EXPORT_DATA_ERROR);
        }
    }

    // 配置一个缓存唯一的key, 读取数据时,先从缓存中获取数据,获取不到再执行方法
    // 需要在RedisConfig中进行配置
    @Cacheable(value = "finance:dictList",key = "{#parentId}")
    @ApiOperation("根据上级ID获取子节点列表数据")
    @GetMapping("/list/{parentId}")
    public Response<Object> listByParentId(
            @ApiParam("上级节点ID")
            @PathVariable("parentId") Long parentId){
        // List<Dict> dicts = null;
        // try {
        //     dicts = (List<Dict>) redisTemplate.opsForValue().get("finance:dictList:"+parentId);
        //     if(dicts != null){
        //        log.info("从Redis中取值");
        //         return Response.ok(dicts);
        //     }
        // } catch (Exception e) {
        //     log.error("redis读取异常：" + ExceptionUtils.getStackTrace(e));
        //     //此处不抛出异常，继续执行后面的代码
        // }
        // log.info("从数据库中取值");
        // dicts = dictService.listByPatentId(parentId);
        // //将数据存入redis
        // try {
        //     redisTemplate.opsForValue().set("finance:dictList:" + parentId, dicts, 5, TimeUnit.MINUTES);
        //     log.info("数据存入redis");
        // } catch (Exception e) {
        //     log.error("redis写入异常：" + ExceptionUtils.getStackTrace(e));
        //     //此处不抛出异常，继续执行后面的代码
        // }
        //  return Response.ok(dicts);
        return Response.ok(dictService.listByPatentId(parentId));
    }

    // 配置缓存失效
    @CacheEvict(value = "finance:dictList",key = "#dict.parentId")
    @ApiOperation("保存字典")
    @PostMapping
    public Response<Object> save(@RequestBody Dict dict){
        dictService.save(dict);
        return Response.ok().message("保存成功");
    }

    @Caching(evict = {
            @CacheEvict(value = "finance:dictList",key = "#dict.parentId"),
            @CacheEvict(value = "finance:dict",key = "#dict.id"),
    })
    @ApiOperation("更新字典")
    @PutMapping
    public Response<Object> update(@RequestBody Dict dict){
        dictService.updateById(dict);
        return Response.ok().message("更新成功");
    }

    @Cacheable(value = "finance:dict",key = "{#id}")
    @ApiOperation("按照ID获取字典信息")
    @GetMapping("/{id}")
    public Response<Object> getById(
            @ApiParam("字典ID")
            @PathVariable("id")
                    Long id){
        Dict dict = dictService.getById(id);
        Assert.notNull(dict,ResponseEnum.DATA_NOT_EXIST);
        return Response.ok(dictService.getById(id));
    }

    @CacheEvict(value = "finance:dictList",key = "#result.data")
    @ApiOperation("按照ID删除字典")
    @DeleteMapping("/{id}")
    public Response<Long> deleteById(
            @ApiParam("字典ID")
            @PathVariable("id")
            Long id){
        Long parentId = dictService.getById(id).getParentId();
        dictService.removeById(id);
        if (dictService.hasChildren(id)){
            throw new BusinessException("字典有下一级,不能删除", 333);
        }
        return Response.ok(parentId).message("删除成功");
    }

}

